#ifndef __CACHE_H__
#define __CACHE_H__

#include "common.h"

#define CACHE_1_SIZE (64 * 1024)
#define CACHE_1_BLOCK_SIZE 64
#define CACHE_1_BLOCK_BITS 6
#define CACHE_1_WAY_SIZE 8
#define CACHE_1_WAY_BITS 3
#define CACHE_1_SET_SIZE 128
#define CACHE_1_SET_BITS 7

typedef struct {
    bool valid_bit;
    uint32_t tag;
    uint8_t data[CACHE_1_BLOCK_SIZE];
} CacheLine1;

CacheLine1 cache1[CACHE_1_SET_SIZE * CACHE_1_WAY_SIZE];

#define CACHE_2_SIZE (4 * 1024 * 1024)
#define CACHE_2_BLOCK_SIZE 64
#define CACHE_2_BLOCK_BITS 6
#define CACHE_2_WAY_SIZE 16
#define CACHE_2_WAY_BITS 4
#define CACHE_2_SET_SIZE 4096
#define CACHE_2_SET_BITS 12

typedef struct {
    bool valid_bit;
    bool dirty_bit;
    uint32_t tag;
    uint8_t data[CACHE_2_BLOCK_SIZE];
} CacheLine2;

CacheLine2 cache2[CACHE_2_SET_SIZE * CACHE_2_WAY_SIZE];

void init_cache();
uint32_t cache1_read(hwaddr_t, size_t);
void cache1_write(hwaddr_t, size_t, uint32_t);

uint32_t cache2_read(hwaddr_t);
void cache2_write(hwaddr_t, size_t, uint32_t);

#endif